@page "/CallWebAPI"
@inject HttpClient Http

<h1>Call a Web API from Blazor</h1>

<h2>Blazor Example</h2>

<p>This example requires a running web API based on the sample app for the <a href="https://docs.microsoft.com/aspnet/core/tutorials/first-web-api">Tutorial: Create a web API with ASP.NET Core</a> topic. This Blazor sample app makes requests to the web API at <code>https://localhost:10000/api/TodoItems</code>. If a different web API address is used, update the <code>ServiceEndpoint</code> constant value in the Razor component's <code>@@code</code> block.</p>

<p>The Blazor sample app makes a <a href="https://docs.microsoft.com/aspnet/core/security/cors">cross-origin resource sharing (CORS)</a> request from <code>http://localhost:5000</code> or <code>https://localhost:5001</code> to the web API service app. Add the following CORS middleware configuration to the web API's service's <code>Startup.Configure</code> method:</p>

<pre><code>app.UseCors(policy => 
    policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
    .AllowAnyMethod()
    .WithHeaders(HeaderNames.ContentType));</code></pre>

<p>Adjust the domains and ports of <code>WithOrigins</code> as needed for the Blazor app.</p>

<p>By default, ASP.NET Core apps use ports 5000 (HTTP) and 5001 (HTTPS). To run both apps on the same machine at the same time for testing, use a different port for the web API app (for example, port 10000). For more information on setting the port, see the <a href="https://docs.microsoft.com/aspnet/core/fundamentals/servers/kestrel#endpoint-configuration">Kestrel web server implementation: Endpoint configuration</a>.</p>

<h3>Todo Items</h3>

@if (_todoItems == null)
{
    <p>No Todo Items found.</p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th class="text-center">Complete</th>
                <th>Name</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <tr id="editRow" style="display:@_editRowStyle">
                <td class="text-center">
                    <input type="checkbox" @bind="_editItem.IsComplete" />
                </td>
                <td>
                    <input @bind="_editItem.Name" />
                </td>
                <td class="text-center">
                    <button class="btn btn-success" @onclick="@SaveItem">Save</button>
                    <button class="btn btn-danger" @onclick="@(() => _editRowStyle = "none")">Cancel</button>
                </td>
            </tr>
            @foreach (var item in _todoItems)
            {
                <tr>
                    <td class="text-center">
                        @if (item.IsComplete)
                        {
                            <span>&#10004;</span>
                        }
                    </td>
                    <td>@item.Name</td>
                    <td class="text-center">
                        <button class="btn btn-warning" @onclick="@(() => EditItem(item.Id))">Edit</button>
                        <button class="btn btn-danger" @onclick="@(async () => await DeleteItem(item.Id))">Delete</button>
                    </td>
                </tr>
            }
            <tr id="addRow">
                <td></td>
                <td>
                    <input @bind="_newItemName" placeholder="New Todo Item" />
                </td>
                <td class="text-center">
                    <button class="btn btn-success" @onclick="@AddItem">Add</button>
                </td>
            </tr>
        </tbody>
    </table>
}

<HTTPRequestTester />

@code {
    private const string ServiceEndpoint = "https://localhost:10000/api/TodoItems";
    private TodoItem[] _todoItems;
    private TodoItem _editItem = new TodoItem();
    private string _editRowStyle = "none";
    private string _newItemName;

    protected override async Task OnInitializedAsync() => await GetTodoItems();

    private async Task GetTodoItems() => _todoItems = await Http.GetJsonAsync<TodoItem[]>(ServiceEndpoint);

    private void EditItem(long id)
    {
        var editItem = _todoItems.Single(i => i.Id == id);
        _editItem = new TodoItem { Id = editItem.Id, Name = editItem.Name, IsComplete = editItem.IsComplete };
        _editRowStyle = "table-row";
    }

    private async Task AddItem()
    {
        var addItem = new TodoItem { Name = _newItemName, IsComplete = false };
        await Http.PostJsonAsync(ServiceEndpoint, addItem);
        _newItemName = string.Empty;
        await GetTodoItems();
        _editRowStyle = "none";
    }

    private async Task SaveItem()
    {
        await Http.PutJsonAsync($"{ServiceEndpoint}/{_editItem.Id}", _editItem);
        await GetTodoItems();
        _editRowStyle = "none";
    }

    private async Task DeleteItem(long id)
    {
        await Http.DeleteAsync($"{ServiceEndpoint}/{id}");
        await GetTodoItems();
        _editRowStyle = "none";
    }

    private class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}
